-- ======================================================================
-- Hell Logic Sniffer Addon 
-- 
-- Copyright 2013 Hell-Prototypes
--
-- http://www.hellprototypes.com/
-- ======================================================================

ModuleClass = "LS_PLUGIN"
ModuleName  = "IC Card Analyse"
ModuleTip   = "Analyse IC Card(T=0) decoded data"

g_channel_number_from_input = false
g_Decoded_Data = {}
g_Decoded_Data_Index = 1

function next_decoded_data()
	while g_Decoded_Data_Index < #g_Decoded_Data do
		local decode_data = g_Decoded_Data[g_Decoded_Data_Index+1]
		g_Decoded_Data_Index = g_Decoded_Data_Index + 2
		if type(decode_data) == "string" then
			if string.len(decode_data) == 3 then
				return decode_data:sub(1,2)
			end
		end
	end

	return nil
end

function get_current_channel()
	local param = LS_API.GetCommonParameter()
	if #param < 4 then
		LS_API.MessageBox("<I2C Analyse> Error param : table size : " .. #param)
		return -1
	end

	return param[4]
end

function input_channel_number()
	local channel = LS_API.InputBox(0, "Input channel num(0~15):")
    if channel == nil or channel >= 16 or channel < 0 then
        return -1;
    end

	return channel
end

function main ()
    local current_channel = get_current_channel()
    if current_channel < 0 then
		current_channel = input_channel_number()
		if current_channel < 0 then
			LS_API.MessageBox("Error channel num: " .. channel .. ", End Work.")
			return
		end
		g_channel_number_from_input = true
    end

    g_Decoded_Data = LS_API.GetChannelDecodedData(current_channel)
    
    if type(g_Decoded_Data) ~= "table" then
		if g_channel_number_from_input == false then
			current_channel = input_channel_number()
			if current_channel < 0 then
				LS_API.MessageBox("Error channel num: " .. current_channel .. ", End Work.")
				return
			end
			g_Decoded_Data = LS_API.GetChannelDecodedData(current_channel)
			if type(g_Decoded_Data) ~= "table" then
				LS_API.MessageBox("No decoded data found in channel : " .. current_channel)
				return
			end
		else
			LS_API.MessageBox("No decoded data found in channel : " .. current_channel)
			return
		end
		return
	end

    LS_API.ReportPushBack("========================================================")
    LS_API.ReportPushBack("IC card data analyse, Decode data length : " .. #g_Decoded_Data/2)
	LS_API.ReportPushBack("========================================================\r\n")

	local TS = next_decoded_data()
	local TS_Num = HexToNum(TS)
	local firstCLA = ""
	if TS_Num == 0x3B then
		LS_API.ReportPushBack("=== ATR Analyse Start ===")
		LS_API.ReportPushBack(" TS: " .. TS)
		ATR_Process()
		LS_API.ReportPushBack("=== ATR Analyse End ===\r\n")
		firstCLA = nil
	elseif TS_Num == 0x3F then
		LS_API.MessageBox("Unsupported : T=1 IC Card protocol : " .. current_channel)
		return
	elseif TS_Num == nil then
		LS_API.ReportPushBack("===No IC Card data found===\r\n")
		return
	else
		firstCLA = TS
	end

	T0_protocol_process(firstCLA)
end


function HexToNum(StrHex)
	return tonumber(StrHex, 16)
end

function list_TABCDx(mask, x)
	--TAx
	if (mask & 0x10) > 0 then
		LS_API.ReportPushBack("TA" .. x .. ": " .. next_decoded_data())
	end
	--TBx
	if (mask & 0x20) > 0 then
		LS_API.ReportPushBack("TB" .. x .. ": " .. next_decoded_data())
	end
	--TCx
	if (mask & 0x40) > 0 then
		LS_API.ReportPushBack("TC" .. x .. ": " .. next_decoded_data())
	end
	--TDx
	if (mask & 0x80) > 0 then
		local TDx = next_decoded_data()
		LS_API.ReportPushBack("TD" .. x .. ": " .. TDx)
		return (HexToNum(TDx) & 0xF0)
	end

	return 0
end

function ATR_Process()
	local T0 = next_decoded_data()
	local T0_Num = HexToNum(T0)
	local next_mask = (T0_Num & 0xF0)
	local history_len = (T0_Num & 0x0F)
	local x = 1
	LS_API.ReportPushBack(" T0: " .. T0)
	while next_mask > 0 do
		next_mask = list_TABCDx(next_mask, x)
		x = x + 1
	end
	if history_len > 0 then
		local history = ""
		for i=1, history_len do
			 history = history .. next_decoded_data() .. " "
		end
		LS_API.ReportPushBack("History data: " .. history )
	else
		LS_API.ReportPushBack("No history data:")
	end
end

function get_TTL_command()
	local _CLA, _INS, _P1, _P2, _P3
	if firstCLA ~= nil then
		_CLA = firstCLA
	else
		_CLA = next_decoded_data()
	end
	_INS = next_decoded_data()
	_P1  = next_decoded_data()
	_P2  = next_decoded_data()
	_P3  = next_decoded_data()
	
	return _CLA, _INS, _P1, _P2, _P3
end

function get_data_section(SW1, lc_le)
	local _data = "[" .. SW1 .. "] "
	for i=1, lc_le do
		 _data = _data .. next_decoded_data() .. " "
	end
	LS_API.ReportPushBack(_data)
end

function T0_protocol_process(firstCLA)
	local CLA, INS, P1, P2, P3
	LS_API.ReportPushBack("=== T=0 APDU Analyse Start ===")

	while true do
		CLA, INS, P1, P2, P3 = get_TTL_command(firstCLA)
		if CLA and INS and P1 and P2 and P3 then
			LS_API.ReportPushBack("\r\n" .. CLA .. " " .. INS .. " " .. P1 .. " " .. P2 .. " " .. P3)
			local SW1 = next_decoded_data()
			if SW1 then
				if SW1 == INS then
					get_data_section(SW1, HexToNum(P3))
					local _SW1 = next_decoded_data()
					local _SW2 = next_decoded_data()
					LS_API.ReportPushBack(_SW1 .. " " .. _SW2)
				elseif HexToNum(SW1) == ((~(HexToNum(INS))) +1) then
					get_data_section(SW1, HexToNum(P3))
				elseif SW1 == "60" then
					LS_API.ReportPushBack("FIXME: Unsupported Procedure Byte Value: 60H")
					break
				else
					local SW2 = next_decoded_data()
					LS_API.ReportPushBack(SW1 .. " " .. SW2)
				end
			else
				break
			end
		else
			break
		end
		firstCLA = nil
	end
	LS_API.ReportPushBack("=== T=0 APDU Analyse End ===\r\n")
end



